#include <iostream>
#include <string.h>
#include <unistd.h>
#include <unordered_map>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define Print "[%s@%s %s]# "
//命令行参数表
#define MAXARGC 128
char* g_argv[MAXARGC];
int g_argc = 0; 
int lastcode = 0;
// 环境变量表
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs = 0;

// 3. 别名映射表
std::unordered_map<std::string, std::string> alias_list;

void InitEnv()
{
    extern char **environ;
    g_envs = 0;
    for(; environ[g_envs]; g_envs++){
        g_env[g_envs] = (char*)malloc(strlen(environ[g_envs])+1);
        strncpy(g_env[g_envs], environ[g_envs], strlen(environ[g_envs])+1);
    }   
}


char* Getenv(const char* cmp)
{
    for(int i = 0; i < g_envs; i++)
    {
        char* A = strstr(g_env[i],cmp);
        if (A)
        {
            char* B = strstr(A,"=");
            return B+1;
        }
    }
    return nullptr;
}


bool CommandParse(char* Gmand);
std::string DirName(const char *pwd);

void PrintCommandPrompt()
{
    const char* Username = Getenv("USER");
    const char* Hostname = Getenv("HOSTNAME");
    const char* Pwd = Getenv("PWD");
    char buffer[1024];
    
    const char* haha = DirName(Pwd).c_str();
    snprintf(buffer,sizeof(buffer),Print,Username,Hostname,haha);
    std::cout << buffer;
    fflush(stdout);
}


std::string DirName(const char *pwd)
{
    std::string str = pwd;
    if(str == "/")
    {
        return str;
    }
    auto pos = str.rfind('/');
    if (pos == std::string::npos)
    {
        return "BUG?"; 
    }
    return str.substr(pos + 1);
}



//2. 获取用户输入的命令
bool GetCommandLine(char *Gmand)
{
    //char Gmand1[MAXARGC] = "alias ll='ls -l'\n";
    //strcpy(Gmand,Gmand1);
    //Gmand[8] = '\n'; 
    char* c = fgets(Gmand,MAXARGC,stdin);
    if (strlen(Gmand) < 2)
    {
        return false;
    }
       // printf("%s\n",c);
       // printf("%s\n",Gmand);
       // int len = strlen(Gmand);
    Gmand[strlen(Gmand)-1] = 0;
    //CommandParse(Gmand);
    return true;
}

//3. 命令行分析 "ls -a -l" -> "ls" "-a" "-l"
bool CommandParse(char *Gmand)
{
    g_argc = 0;
    //g_argv[g_argc++] = strtok(Gmand," ");
   // while((bool)(g_argv[g_argc++] = strtok(nullptr," ")));
   // printf("%d\n",g_argc);
   // g_argc--;
   // return g_argc > 0 ? true:false;
    //string Parse = Gmand;
    //g_argc = 0;
    //g_argv[g_argc++] = strtok(Gmand," ");
    char* token = strtok(Gmand," ");
    //strcpy(g_argv[g_argc++],token);
    g_argv[g_argc++] = token;
    if (strcmp(token,"alias") == 0)
    {
        token = strtok(nullptr,"");
        if(token)
        {
            g_argv[g_argc++] = token;
        }
        return true;
    }
    while (token!= NULL)
    {
        token = strtok(nullptr," ");
        g_argv[g_argc++] = token;
        //strcpy(g_argv[g_argc++],token);
    }
    g_argc--;
    //g_argv[g_argc++] = NULL;
    return g_argc > 0 ? true:false;
}

void PrintCommand()
{
    int j = 0;
    while(g_argv[j] != NULL)
    {
        printf("%d |%s|\n",j,g_argv[j]);
        j++;
        fflush(stdout);
    }
   // g_argc = 0;
}

void Execute();
//4. 检测别名
bool CheckAlias()
{

    if (strcmp(g_argv[0],"alias") == 0 && g_argc == 2)
    {
        //alias la='ls -a'
        //if(strlen(g_argv[1]) < 2)
        //  return false;
        //K
        char* cmp1 = strtok(g_argv[1], "=");
        // Val
        char* cmp2 = strtok(nullptr, "=");
        //去除''
        //判断是否插入
        if(cmp2 && strlen(cmp2) > 2)
        {
            cmp2 = cmp2 + 1;
            cmp2[strlen(cmp2) - 1] = 0;
        }
        std::string cmp3 = alias_list[cmp1];
        //插入命令
        if(cmp3.empty() && *cmp2)
        {
            alias_list[cmp1] = cmp2;
        }
        else if(!cmp3.empty())
        {
            if(*cmp2)
            {
                std::cout << cmp1 << "命令已存在" << std::endl;
            }
        }
        return true;
    }
    //调用
    else{
        std::string cmp = alias_list[g_argv[0]];
        char* cmp4 = new char (sizeof(char) * cmp.length() + 1);
        std::strcpy(cmp4,cmp.c_str());
        if(!cmp.empty() && g_argc == 1)
        {
            if(CommandParse(cmp4))
            {
                Execute();
                return true;
            }
        }
    }
    return false;
}
//5. 判断是否为内建命令

void AddEnv(const char *item)
{
    int index = 0;
    while(g_env[index])
    {
        index++;
    } 
    g_env[index] = (char*)malloc(strlen(item)+1);
    strncpy(g_env[index], item, strlen(item)+1);
    g_env[++index] = nullptr;
    g_envs++;
}

bool CheckAndExecBuiltin()
{
    if(strcmp(g_argv[0], "cd") == 0)
    {
    // 内建命令
        if(g_argc == 2)
        {
            //if(g_argv[1] = "..")
            //{
            //    char* Pwd = Getenv("PWD");
            //    char* Oldpwd = Getenv("OLDPWD");
            //}
            //else{

            //}
            chdir(g_argv[1]);

            //偷个懒
            lastcode = 0;
        }
        else
        {
            lastcode = 1;
        }
        return true;
    } 
    else if(strcmp(g_argv[0], "export") == 0)
    {
        // export也是内建命令
        if(g_argc == 2)
        {
            AddEnv(g_argv[1]);
            lastcode = 0;
        }
        else
        {
            lastcode = 2;
        }
            return true;
    } 
    else if(strcmp(g_argv[0], "env") == 0)
    {
        for(int i = 0; g_env[i]; i++)
        {
            printf("%s\n", g_env[i]);
        }
        lastcode = 0;
        return true;
    }
    else if(strcmp(g_argv[0], "echo") == 0)
    {
        if(g_argc == 2)
        {
    // echo $?
    // echo $PATH
    // echo hello
            if(g_argv[1][0] == '$')
            {
                if(g_argv[1][1] == '?')
                {
                    printf("%d\n", lastcode);
                    lastcode = 0;
                }
            } 
            else
            {
                printf("%s\n", g_argv[1]);
                lastcode = 0;
            }
        }
        else
        {
            lastcode = 3;
        } 
        return true;
    } 
    else if(g_argc == 1 && strcmp(g_argv[0], "pwd") == 0 )
    {
        printf("%s\n",Getenv("PWD"));
        lastcode = 0;
        return true;
    }
    return false;
} 

//6. 子进程执行非内建命令
void Execute()
{
    //char** haha = g_argv;
    pid_t pid = fork();
    if (pid == 0)
    {
       // char* hehe[4] = {"ls", "-l", "-a", NULL};
       // char* hehe[4];
       // hehe[0] = g_argv[0];
       // hehe[1] = g_argv[1];
       // hehe[2] = g_argv[2];
       // hehe[3] = g_argv[3];
        if (execvp(g_argv[0],g_argv) == -1)
        {
            perror("execvp执行失败");
            exit(1);
        }
    }
    wait(NULL);
}
int main()
{   
    // shell 启动的时候，从系统中获取环境变量
    // 我们的环境变量信息应该从父shell统一来
    InitEnv();
    char Getmand[MAXARGC] = {'\0'};
    while(1)
    {
         //1. 打印命令行提示符(使用系统的环境变量表)
         PrintCommandPrompt();
         //2. 获取用户输入的命令
         if(!GetCommandLine(Getmand))
             continue;
         //3. 命令行分析 "ls -a -l" -> "ls" "-a" "-l"
         printf("%s\n",Getmand);
         if(!CommandParse(Getmand))
         //4. 检测别名
         if(CheckAlias())
             continue;
         //5. 判断是否为内建命令
         if(CheckAndExecBuiltin())
             continue;
         //6. 子进程执行非内建命令
         //PrintCommand();
         Execute();
         //sleep(2);
    }
    return 0;
}

